import time
import datetime
import json
import os
# 这里有错误,不能这样,要确保time.time()调用的是标准库的time模块
# from datetime import time, datetime

from typing import Dict

import psutil

from Kylin_test.src.model.models import Disk


# 磁盘相关信息
class DiskMonitor:
    """磁盘信息监控类，包含统计信息、I/O更新和时间统计"""

    def __init__(self):
        # 初始化历史I/O统计
        self.prev_io_counters = None
        self.last_update_time = time.time()

        # 初始化时间统计
        self.io_time_start = time.time()
        self.read_time_ms = 0.0
        self.write_time_ms = 0.0
        self.busy_time_ms = 0.0

    # 采用默认参数,如果没有传指定哪个盘,全部采取
    def get_disk_usage(self, partition: str = "/") -> Disk:
        """获取指定分区的磁盘使用情况"""
        try:
            usage = psutil.disk_usage(partition) # 获取psutil中的disk_usage函数
            io_counters = psutil.disk_io_counters(perdisk=False)
            now = datetime.datetime.now()
            timestamp = int(now.timestamp())

            # 计算I/O增量
            read_count, write_count, read_bytes, write_bytes = 0, 0, 0, 0
            if self.prev_io_counters:
                time_diff = time.time() - self.last_update_time
                if time_diff > 0:
                    read_count = io_counters.read_count - self.prev_io_counters.read_count
                    write_count = io_counters.write_count - self.prev_io_counters.write_count
                    read_bytes = io_counters.read_bytes - self.prev_io_counters.read_bytes
                    write_bytes = io_counters.write_bytes - self.prev_io_counters.write_bytes

                    # 更新时间统计
                    self._update_io_time_stats(
                        read_count, write_count,
                        read_bytes, write_bytes,
                        time_diff
                    )

            # 保存当前状态用于下次增量计算
            self.prev_io_counters = io_counters
            self.last_update_time = time.time()

            return Disk(
                disk_timestamp=timestamp,
                disk_time=now,
                disk_total=usage.total,
                disk_used=usage.used,
                disk_free=usage.free,
                disk_percentage_usage=round(usage.percent),
                disk_read_count=read_count,
                disk_write_count=write_count,
                disk_read_bytes=read_bytes,
                disk_write_bytes=write_bytes
            )
        except Exception as e:
            # 错误处理：权限问题、挂载点不存在等
            print(f"Error getting disk stats: {e}")
            return Disk()

    def _update_io_time_stats(self, read_count: int, write_count: int,
                              read_bytes: int, write_bytes: int,
                              time_diff: float):
        """更新I/O时间统计信息"""
        # 模拟内核时间统计 (毫秒)
        if read_count > 0 or write_count > 0:
            # 假设每次I/O操作平均耗时 (基于经验值)
            avg_read_time = 5.0  # ms
            avg_write_time = 8.0  # ms

            # 计算读写时间
            self.read_time_ms += read_count * avg_read_time
            self.write_time_ms += write_count * avg_write_time

            # 计算磁盘繁忙时间 (基于吞吐量和操作频率)
            throughput = (read_bytes + write_bytes) / time_diff
            ops_rate = (read_count + write_count) / time_diff

            # 经验公式：繁忙时间 = 基础时间 + 吞吐量因子 + 操作频率因子
            base_time = min(1000 * time_diff, 1000)  # 不超过1000ms
            throughput_factor = throughput / (1024 * 1024) * 50  # 每MB/s增加50ms
            ops_factor = ops_rate / 100 * 10  # 每100IOPS增加10ms

            self.busy_time_ms += base_time + throughput_factor + ops_factor

    def get_io_time_stats(self) -> Dict[str, float]:
        #这里的获取累计IO的时间统计有误做了修改,修正了 get_io_time_stats 方法中的繁忙时间百分比计算
        """获取累积的I/O时间统计信息"""
        total_time = time.time() - self.io_time_start
        busy_percentage = (self.busy_time_ms / (total_time * 1000)) * 100 if total_time > 0 else 0

        return {
            "read_time_ms": round(self.read_time_ms, 2),
            "write_time_ms": round(self.write_time_ms, 2),
            "busy_time_ms": round(self.busy_time_ms, 2),
            "busy_percentage": round(busy_percentage, 1)
        }

        # """获取累积的I/O时间统计信息"""
        # return {
        #     "read_time_ms": round(self.read_time_ms, 2),
        #     "write_time_ms": round(self.write_time_ms, 2),
        #     "busy_time_ms": round(self.busy_time_ms, 2),
        #     "busy_percentage": round(self.busy_time_ms / (time.time() - self.io_time_start) / 10, 1)
        # }

    def get_detailed_stats(self, partition: str = "/") -> Dict:
        """获取详细的磁盘统计信息"""
        disk = self.get_disk_usage(partition)
        time_stats = self.get_io_time_stats()

        return {
            ## "basic": disk.dict(),  # 这种写法已经被淘汰了
            # PydanticDeprecatedSince20: The `dict` method is deprecated; use `model_dump` instead.
            # Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at

            "basic":disk.model_dump(),
            "time_stats": time_stats                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   ,
            "throughput": {
                "read_mbps": round(disk.disk_read_bytes / (1024 * 1024), 2),
                "write_mbps": round(disk.disk_write_bytes / (1024 * 1024), 2)
            },
            "iops": {
                "read_iops": disk.disk_read_count,
                "write_iops": disk.disk_write_count
            }
        }


# 使用示例
# 这里做下调整,放在循环外部即可
# 这里就是正确调用的示例
def json_serial(obj):
    """JSON 序列化辅助函数"""
    if isinstance(obj, (datetime.datetime, datetime.date)):
        return obj.isoformat()
    raise TypeError(f"Type {type(obj)} not serializable")

if __name__ == "__main__":
    monitor = DiskMonitor()

    # 这里新增一行分区,方便监控disk_info = monitor.get_disk_usage()
    # 让分区名作为参数传入，方便监控不同分区
    partition = "C:\\" # 监控C盘

    # 这里添加了一个退出条件,否则只能在终端强制关闭
    try:
        while True:
            # 第一次调用获取基础信息
            # 测试了下本人的磁盘使用情况,没有问题
            # Initial disk stats:
            # Total: 464.63 GB
            # Used: 402.03 GB
            # Free: 62.61 GB
            # Usage: 86 %
            print("Initial disk stats:")

            # disk_info = monitor.get_disk_usage()
            # 这里做了优化,目的是方便监控不同分区
            disk_info = monitor.get_disk_usage(partition)

            print(f"Total: {disk_info.disk_total / (1024 ** 3):.2f} GB")
            print(f"Used: {disk_info.disk_used / (1024 ** 3):.2f} GB")
            print(f"Free: {disk_info.disk_free / (1024 ** 3):.2f} GB")
            print(f"Usage: {disk_info.disk_percentage_usage}%")

            print("________________________________________________________")

            # 获取采集写入前的I/O统计
            disk_info_before = monitor.get_disk_usage(partition)
            print("写入前统计：")
            print(f"write_bytes: {disk_info_before.disk_write_bytes}")
            print(f"write_count: {disk_info_before.disk_write_count}")

            print("________________________________________________________")

            print("等待写入文件,查看增量是否变化")

            # 为了观察到往文件写入数据后,能观察到写入次数和写入字节数,这里特意写了一些例子,方便观察
            # 同时遇到了一些问题,写入时被缓存,未刷新到磁盘中.这是因为文件内核缓冲区并未刷新到磁盘中,因此这里采用强制刷新的方法.
            file_path = "C://testfile.bin"
            with open("file_path", "wb") as f:
                f.write(b"0" * 1024 * 1024 * 100)  # 写入100MB
                f.flush()
                os.fsync(f.fileno())  # 强制写入磁盘

            print("写入完毕")

            time.sleep(2)

            # 写入后采集
            disk_info_after = monitor.get_disk_usage(partition)

            # print(f"写入前 write_bytes: {disk_info_before.disk_write_bytes}") # 代码有误,不必重复一遍
            print(f"写入后 write_bytes: {disk_info_after.disk_write_bytes}")
            print(f"本次写入字节数: {disk_info_after.disk_write_bytes - disk_info.disk_write_bytes}")

            # 等待一段时间后再次调用
            # 第一次采集增量必为0,循环输出查看增量是否改变
            print("等待一段时间再次调用")
            time.sleep(2)

            print("\nAfter 2 seconds:")

            # 这里的代码是没有必要的
            # # 这里也要传
            # disk_info = monitor.get_disk_usage(partition)
            # print(f"Read bytes: {disk_info.disk_read_bytes}")
            # print(f"Write bytes: {disk_info.disk_write_bytes}")

            # 获取详细统计
            print("\nDetailed statistics:")
            detailed_stats = monitor.get_detailed_stats(partition)

            # 下面这行代码不够美化
            # print(detailed_stats)
            # 但是美化过程中出现了报错,在 json.dumps 里加一个 default 参数
            # print(json.dumps(detailed_stats, indent=2, ensure_ascii=False))

            print(json.dumps(detailed_stats, indent=2, ensure_ascii=False, default=json_serial))

            # 清理测试文件
            if os.path.exists(file_path):
                os.remove(file_path)

            time.sleep(3)
            print("________________________________________________________")

    except KeyboardInterrupt:
        print("监控已手动终止。")